//////////////////////////////////////////////////////////////////////////
// $Id: Texture.cpp,v 1.1 2009/04/03 12:46:11 sunjun Exp $
//////////////////////////////////////////////////////////////////////////

#include "Local.h"

//////////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////////

NAMESPACE_BEGIN

//////////////////////////////////////////////////////////////////////////

	//////////////////////////////////////////////////////////////////////////
	// DDS
	//////////////////////////////////////////////////////////////////////////

	#pragma pack(push,1)

	// DDPixelFormat flags
	enum 
	{
		DDPF_ALPHAPIXELS	= 0x00000001l,
		DDPF_ALPHA          = 0x00000002l,
		DDPF_FOURCC         = 0x00000004l,
		DDPF_RGB            = 0x00000040l,		
		DDPF_LUMINANCE      = 0x00020000l
	};

	struct DDPixelFormat
	{
		U32	Size;
		U32	Flags;
		U32	FourCC;
		U32	RGBBitCount;
		U32	RBitMask;
		U32	GBitMask;
		U32	BBitMask;
		U32	RGBAlphaBitMask;
	};	

	// DDCaps2 flags
	enum 
	{
		DDSCAPS_TEXTURE	= 0x00001000l,
		DDSCAPS_COMPLEX	= 0x00000008l,
		DDSCAPS_MIPMAP	= 0x00400000l,
		DDSCAPS2_VOLUME	= 0x00200000l,
		DDSCAPS2_CUBEMAP= 0x00000200
	};

	struct DDCaps2
	{
		U32	Caps1;
		U32	Caps2;
		U32	Reserved[2];
	};	

	// DDSurfaceDesc2 flags
	enum 
	{
		DDSD_CAPS			= 0x00000001l,
		DDSD_HEIGHT			= 0x00000002l,
		DDSD_WIDTH			= 0x00000004l,
		DDSD_PITCH			= 0x00000008l,
		DDSD_PIXELFORMAT	= 0x00001000l,		
		DDSD_MIPMAPCOUNT	= 0x00020000l,
		DDSD_LINEARSIZE		= 0x00080000l,
		DDSD_DEPTH			= 0x00800000l
	};

	struct DDSurfaceDesc2
	{
		U32	Size;
		U32	Flags;
		U32	Height;
		U32	Width;
		U32	PitchOrLinearSize;
		U32	Depth;
		U32	MipMapCount;
		U32	Reserved1[11];
		DDPixelFormat	PixelFormat;
		DDCaps2			Caps;
		U32	Reserved2;
	};

	#define FOURCC_DXT1  (MAKE_FOURCC('D','X','T','1'))	
	#define FOURCC_DXT3  (MAKE_FOURCC('D','X','T','3'))
	#define FOURCC_DXT5  (MAKE_FOURCC('D','X','T','5'))

	#pragma pack(pop)

	//////////////////////////////////////////////////////////////////////////

	Texture::Texture( const Context* rc ) : mHandle(NULL) 
	{
		CHECK(rc);
		mRCPtr = (Context*)rc;
	}

	Texture::~Texture() 
	{
		if((IDirect3DBaseTexture9*)mHandle){((IDirect3DBaseTexture9*)mHandle)->Release(); mHandle = NULL;}
	}

	//////////////////////////////////////////////////////////////////////////

	/*
	====================
	handle
	====================
	*/
	INLINE HANDLE Texture::handle() const
	{
		return mHandle;
	}

	/*
	====================
	load
	====================
	*/
	INLINE VOID Texture::load( const VOID* data, U32 size )
	{
		CHECK( mHandle == NULL );		

		U32 data_pos = 0;
		const U8* data_ptr = (U8*)data;

		// check the dds magic
		U32 magic = *(U32*)(data_ptr+data_pos);
		data_pos += sizeof(U32);
		CHECK(magic == MAKE_FOURCC('D','D','S',' '));

		// get the DDSurfaceDesc2
		DDSurfaceDesc2& ddsd = *(DDSurfaceDesc2*)(data_ptr+data_pos);
		data_pos += sizeof(DDSurfaceDesc2);

		// create the texture 
		if( ddsd.Caps.Caps2 & DDSCAPS2_VOLUME )
		{
			IDirect3DVolumeTexture9 *d3d9VolumeTexture = NULL;	
			HRESULT hr = D3DXCreateVolumeTextureFromFileInMemoryEx(
				(IDirect3DDevice9*)mRCPtr->handle(),
				data,
				size,
				D3DX_DEFAULT,
				D3DX_DEFAULT,
				D3DX_DEFAULT,
				ddsd.MipMapCount,
				0,
				D3DFMT_UNKNOWN,
				D3DPOOL_MANAGED,
				D3DX_DEFAULT,
				D3DX_DEFAULT,
				0,
				NULL,
				NULL,
				&d3d9VolumeTexture ); 
			if( FAILED(hr) )
			{
				MAssert(VA("Texture::load : create the volume texture is failed(%s)!", DXGetErrorDescription(hr)));
			}

			// get the base texture
			hr = d3d9VolumeTexture->QueryInterface(IID_IDirect3DBaseTexture9, (VOID **)&mHandle);
			if(FAILED(hr))
			{
				MAssert(VA("Texture::load : can't get base texture(%s)!", DXGetErrorDescription(hr)));
			}

			// release the texture
			if( d3d9VolumeTexture ){ d3d9VolumeTexture->Release(), d3d9VolumeTexture = NULL; }

			// store the type
			mType = TT_VOLUME;
		} 
		else if( ddsd.Caps.Caps2 & DDSCAPS2_CUBEMAP )
		{
			IDirect3DCubeTexture9 *d3d9CubeTexture = NULL;	
			HRESULT hr = D3DXCreateCubeTextureFromFileInMemoryEx(
				(IDirect3DDevice9*)mRCPtr->handle(),
				data,
				size,
				D3DX_DEFAULT,
				ddsd.MipMapCount,
				0,
				D3DFMT_UNKNOWN,
				D3DPOOL_MANAGED,
				D3DX_DEFAULT,
				D3DX_DEFAULT,
				0,
				NULL,
				NULL,
				&d3d9CubeTexture ); 
			if( FAILED(hr) )
			{
				MAssert(VA("Texture::load : create the cube texture is failed(%s)!", DXGetErrorDescription(hr)));
			}

			// get the base texture
			hr = d3d9CubeTexture->QueryInterface(IID_IDirect3DBaseTexture9, (VOID**)&mHandle);
			if(FAILED(hr))
			{
				MAssert(VA("Texture::load : can't get base texture(%s)!", DXGetErrorDescription(hr)));
			}

			// release the texture
			if( d3d9CubeTexture ){ d3d9CubeTexture->Release(), d3d9CubeTexture = NULL; }

			// store the type
			mType = TT_CUBEMAP;
		}
		else
		{
			IDirect3DTexture9 *d3d9Texture = NULL;
			HRESULT hr = D3DXCreateTextureFromFileInMemoryEx(
				(IDirect3DDevice9*)mRCPtr->handle(),
				data,
				size,
				D3DX_DEFAULT, 
				D3DX_DEFAULT,
				ddsd.MipMapCount,
				0,
				D3DFMT_UNKNOWN,
				D3DPOOL_MANAGED,
				D3DX_DEFAULT,
				D3DX_DEFAULT,
				0,
				NULL,
				NULL,
				&d3d9Texture ); 
			if( FAILED(hr) )
			{
				MAssert(VA("Texture::load : create the texture is failed(%s)!", DXGetErrorDescription(hr)));
			}

			// get the base texture
			hr = d3d9Texture->QueryInterface(IID_IDirect3DBaseTexture9, (VOID **)&mHandle);
			if(FAILED(hr)) MAssert(VA("Texture::load : can't get base texture(%s)!", DXGetErrorDescription(hr)));

			// release the texture
			if( d3d9Texture ){ d3d9Texture->Release(), d3d9Texture = NULL; }

			// store the type
			mType = TT_TEXTURE;
		}
	}

//////////////////////////////////////////////////////////////////////////

NAMESPACE_END

//////////////////////////////////////////////////////////////////////////
